package engine

import (
	"errors"
	"fmt"
	"gitee.com/kinwyb/workflow/public"
	"gitee.com/kinwyb/workflow/storage"
	"slices"
)

// 校验流是否完整
func flowVerification(flow *Flow) error {
	flowBuildID(flow)
	if flow.NodeCode == "" {
		flow.NodeCode = public.IDGen()
	}
	if flow.NodeName == "" {
		flow.NodeName = flow.NodeCode
	}
	switch flow.NodeType {
	case NodeTypeStart:
		if flow.Child == nil {
			return fmt.Errorf("%s(%s)起始节点必须存在下游节点", flow.NodeName, flow.NodeCode)
		}
		return flowVerification(flow.Child)
	case NodeTypeNormal:
		if flow.Child == nil {
			return fmt.Errorf("%s(%s)常规节点必须存在下游节点", flow.NodeName, flow.NodeCode)
		}
		return flowVerification(flow.Child)
	case NodeTypeRoute:
		if flow.Route == nil && flow.RouteID == "" {
			return fmt.Errorf("%s(%s)判断节点必须存在公式信息", flow.NodeName, flow.NodeCode)
		}
		if flow.Route != nil {
			if flow.Route.Formula == "" {
				return fmt.Errorf("%s(%s)判断节点必须存在判断公式", flow.NodeName, flow.NodeCode)
			}
		}
		if flow.RouteSucc == nil {
			return fmt.Errorf("%s(%s)判断节点成功下游不能为空", flow.NodeName, flow.NodeCode)
		}
		re := flowVerification(flow.RouteSucc)
		if re != nil {
			return re
		}
		if flow.RouteFail == nil {
			return fmt.Errorf("%s(%s)判断节点失败下游不能为空", flow.NodeName, flow.NodeCode)
		}
		re = flowVerification(flow.RouteFail)
		if re != nil {
			return re
		}
		return nil
	case NodeTypeEnd:
		return nil
	default:
		return fmt.Errorf("%s(%s)未知节点类型：%d", flow.NodeName, flow.NodeCode, flow.NodeType)
	}
}

// 生成流节点ID
func flowBuildID(flow *Flow) {
	if flow != nil {
		flow.NodeID = public.IDGenIntString()
		if flow.Child != nil {
			flowBuildID(flow.Child)
		}
		if flow.RouteFail != nil {
			flowBuildID(flow.RouteFail)
		}
		if flow.RouteSucc != nil {
			flowBuildID(flow.RouteSucc)
		}
		if flow.NodeType == NodeTypeRoute {
			routeBuildID(flow.Route)
			if flow.Route != nil {
				flow.RouteID = flow.Route.RouteID
			}
		}
	}
}

// 解析流结构到存储节点
func flowToNode(flow Flow, topNodeID string, level int) ([]storage.Node, []storage.RouteNode, error) {
	if flow.NodeType != NodeTypeStart && topNodeID == "" {
		return nil, nil, fmt.Errorf("顶部节点ID空")
	} else if flow.NodeType == NodeTypeStart && topNodeID != "" {
		return nil, nil, fmt.Errorf("起始节点多余顶部ID")
	}
	if flow.NodeType == NodeTypeStart {
		topNodeID = flow.NodeID
	}
	var routeNodes []storage.RouteNode
	var childrenNodes []storage.Node
	node := storage.Node{
		TopNodeID:   topNodeID,
		NodeID:      flow.NodeID,
		NodeCode:    flow.NodeCode,
		NodeName:    flow.NodeName,
		NodeLevel:   level,
		NodeType:    int(flow.NodeType),
		UserGroupID: flow.UserGroupID,
	}
	switch flow.NodeType {
	case NodeTypeStart, NodeTypeNormal:
		if flow.Child == nil {
			return nil, nil, fmt.Errorf("%s(%s)必须存在下游节点", flow.NodeName, flow.NodeCode)
		}
		node.ChildID = flow.Child.NodeID
		cnodes, croutNodes, cerr := flowToNode(*flow.Child, topNodeID, level+1)
		if cerr != nil {
			return nil, nil, cerr
		}
		childrenNodes = append(childrenNodes, cnodes...)
		routeNodes = append(routeNodes, croutNodes...)
	case NodeTypeRoute:
		if flow.RouteID == "" && flow.Route == nil {
			return nil, nil, fmt.Errorf("%s(%s)判断节点必须存在公式", flow.NodeName, flow.NodeCode)
		}
		if flow.Route != nil && flow.Route.RouteID == "" {
			return nil, nil, fmt.Errorf("%s(%s)判断节点必须存在公式", flow.NodeName, flow.NodeCode)
		}
		if flow.Route != nil {
			node.RouteID = flow.Route.RouteID
		} else {
			node.RouteID = flow.RouteID
		}
		if flow.RouteSucc == nil {
			return nil, nil, fmt.Errorf("%s(%s)判断节点成功必须存在", flow.NodeName, flow.NodeCode)
		}
		node.RouteSuccID = flow.RouteSucc.NodeID
		if flow.RouteFail == nil {
			return nil, nil, fmt.Errorf("%s(%s)判断节点失败必须存在", flow.NodeName, flow.NodeCode)
		}
		node.RouteFailID = flow.RouteFail.NodeID
		if flow.Route != nil {
			rNodes, rerr := routeToNode(*flow.Route, "")
			if rerr != nil {
				return nil, nil, rerr
			}
			routeNodes = append(routeNodes, rNodes...)
		}
		csnodes, csroutenodes, cserr := flowToNode(*flow.RouteSucc, topNodeID, level+1)
		if cserr != nil {
			return nil, nil, cserr
		}
		childrenNodes = append(childrenNodes, csnodes...)
		routeNodes = append(routeNodes, csroutenodes...)
		cfnodes, cfroutenodes, cferr := flowToNode(*flow.RouteFail, topNodeID, level+1)
		if cferr != nil {
			return nil, nil, cferr
		}
		childrenNodes = append(childrenNodes, cfnodes...)
		routeNodes = append(routeNodes, cfroutenodes...)
	}
	return append([]storage.Node{node}, childrenNodes...), routeNodes, nil
}

// FlowSave 流保存
func FlowSave(flow Flow, ctx *public.ContextValue) (string, error) {
	err := flowVerification(&flow)
	if err != nil {
		return "", err
	}
	nodes, routeNodes, err := flowToNode(flow, "", 0)
	if err != nil {
		return "", err
	}
	// 节点ID相同的节点剔除
	var saveNodes []storage.Node
	var nodeIDs []string
	for _, node := range nodes {
		if slices.Contains(nodeIDs, node.NodeID) {
			continue
		}
		nodeIDs = append(nodeIDs, node.NodeID)
		saveNodes = append(saveNodes, node)
	}
	err = storage.FlowSave(saveNodes, routeNodes, ctx)
	if err != nil {
		return "", err
	}
	return saveNodes[0].TopNodeID, nil
}

// FlowQuery 查询一个流
func FlowQuery(flowID string, ctx *public.ContextValue) (*Flow, error) {
	nodes, err := storage.FlowQuery(flowID, ctx)
	if err != nil {
		return nil, err
	}
	if len(nodes) < 1 {
		return nil, fmt.Errorf("工作流不存在")
	}
	var nodeMap = map[string]storage.Node{}
	for _, v := range nodes {
		nodeMap[v.NodeID] = v
	}
	return nodeBuildFlow(flowID, nodeMap)
}

// FlowQueryNodes 查询流程节点列表
func FlowQueryNodes(flowID string, ctx *public.ContextValue) ([]Node, error) {
	nodes, err := storage.FlowQuery(flowID, ctx)
	if err != nil {
		return nil, err
	}
	if len(nodes) < 1 {
		return nil, fmt.Errorf("工作流不存在")
	}
	var ret = make([]Node, len(nodes))
	for i, v := range nodes {
		newNode := Node{Node: v}
		if newNode.NodeType == int(NodeTypeRoute) {
			newNode.Route, _ = RouteQuery(newNode.RouteID)
		}
		ret[i] = newNode
	}
	return ret, nil
}

func nodeBuildFlow(flowID string, nodeMap map[string]storage.Node) (*Flow, error) {
	node := nodeMap[flowID]
	if node.NodeID == "" {
		return nil, fmt.Errorf("节点[%s]不存在", flowID)
	}
	workflow := Flow{
		NodeID:      node.NodeID,
		NodeCode:    node.NodeCode,
		NodeName:    node.NodeName,
		NodeType:    FlowNodeType(node.NodeType),
		UserGroupID: node.UserGroupID,
	}
	switch workflow.NodeType {
	case NodeTypeStart, NodeTypeNormal:
		child, err := nodeBuildFlow(node.ChildID, nodeMap)
		if err != nil {
			return nil, err
		}
		workflow.Child = child
		return &workflow, nil
	case NodeTypeEnd:
		return &workflow, nil
	case NodeTypeRoute:
		route, err := RouteQuery(node.RouteID)
		if err != nil {
			return nil, err
		}
		workflow.Route = route
		workflow.RouteDesc = routeFormulaString(*route)
		succflow, serr := nodeBuildFlow(node.RouteSuccID, nodeMap)
		if serr != nil {
			return nil, serr
		}
		workflow.RouteSucc = succflow
		failFlow, ferr := nodeBuildFlow(node.RouteFailID, nodeMap)
		if ferr != nil {
			return nil, ferr
		}
		workflow.RouteFail = failFlow
		return &workflow, nil
	default:
		return nil, fmt.Errorf("节点[%s]类型未知", workflow.NodeID)
	}
}

// FlowNodeQuery 流程节点查询
func FlowNodeQuery(nodeID string) (storage.Node, error) {
	return storage.FlowNodeQuery(nodeID)
}

// FlowNodeUpdate 流程节点更新
func FlowNodeUpdate(node Node, ctx *public.ContextValue) error {
	if node.NodeID == "" {
		return errors.New("节点ID空")
	}
	var routeNodes []storage.RouteNode
	if node.NodeType == int(NodeTypeRoute) {
		if node.Route != nil {
			routeBuildID(node.Route)
			if node.Route.Formula == "" {
				return fmt.Errorf("节点必须存在判断公式")
			}
			node.RouteID = node.Route.RouteID
		} else if node.RouteID == "" {
			return errors.New("判断节点必须存在判断公式")
		}
		routeNodes, _ = routeToNode(*node.Route, "")
	}
	return storage.FlowNodeUpdate(node.Node, routeNodes, ctx)
}

// FlowDel 工作流删除
func FlowDel(flowID string, ctx *public.ContextValue) error {
	return storage.FlowDel(flowID, ctx)
}

// UserGroupList 用户组列表
func UserGroupList(ctx *public.ContextValue) ([]string, error) {
	return storage.UserGroupList(ctx)
}

// UserGroupUserIDQuery 用户组用户ID列表
func UserGroupUserIDQuery(userGroupName string, ctx *public.ContextValue) ([]string, error) {
	return storage.UserGroupUserIDQuery(userGroupName, ctx)
}

// UserGroupAddUserID 用户组绑定用户
func UserGroupAddUserID(userGroupName string, userID string, ctx *public.ContextValue) error {
	return storage.UserGroupAddUserID(userGroupName, userID, ctx)
}

// UserGroupDelUserID 用户组移除用户
func UserGroupDelUserID(userGroupName string, userID string, ctx *public.ContextValue) error {
	return storage.UserGroupDelUserID(userGroupName, userID, ctx)
}
